#pragma once
#ifndef _FEM_TRIANGLENET_SEARCH_
#define _FEM_TRIANGLENET_SEARCH_

//================================================================================================================================
//================================================================================================================================
// QtCore
#include <QtCore/QList>
#include <QtCore/QVector>
// Локальные
#include "fem/trianglenet.h"
#include "core_global.h"

//================================================================================================================================
//================================================================================================================================
namespace fem
{
    /// Класс, позволяющий ускорить поиск информации о конечноэлементной сетке.
    //
    /// Класс позволяет быстро искать следующую информацию:\n
    /// 1)Какому из треугольных конечных элементов принадлежит заданная точка;\n
    /// 2)Какому материалу соответствует заданный узел конечноэлементной сетки; \n
    /// \n
    /// Все эти действия являются очень трудоемкими при классической для МКЭ организации структур данных. Зачастую для поиска
    /// необходимой информации требуется полный перебор всех элементов сетки. Данный клас, за счет введения нескольких дополнительных
    /// структур данных позволят существенно сократить затраты на поиск за счет хранения расширенной информации о конечноэлементной сетке.
    /// \sa Метод конечных элементов для решения скалярных и векторных задач : учеб. пособие / Ю.Г. Соловейчик, М.Э. Рояк, М.Г. Персова -
    /// Новосибирск: Изд-во НГТУ, 2007. - С. 521-523.
    class CORE_EXPORT TriangleNetSearch
    {
    public:
        /// Разбиение расчётной области на "зоны поиска" (прямоугольники).
        //
        /// Для того, чтобы ускорить поиск конечных элементов в нерегулярной треугольной сетке необходимо "накрыть" расчетную область
        /// прямоугольной сеткой, и в дальнейшем вести поиск только в нужном прямоугольнике. Параметры этой прямоугольной сетки
        /// задаются в конструкторе и уже не могут быть изменены впоследствии.
        /// \param rect_per_row     Число прямоугольников в сетке по горизонтали.
        /// \param rect_per_column  Число прямоугольниклв в сетке по вертикали.
        /// \param rect_width       Ширина прямоугольника.
        /// \param rect_height      Высота прямоугольника.
        TriangleNetSearch(int rect_per_row, int rect_per_column, double rect_width, double rect_height);
        ~TriangleNetSearch();

        /// Сбор информации о конечноэлементной сетке. Позволяет в последствии осуществлять быстрый поиск по сетке.
        void analyzeNet(const TriangleNet &net);

        /// Получение индекса треугольного конечного элемента, которому принадлежит точка с координатами (x,y).
        int findTriangle(const TriangleNet &net, const geometry::_2d::Point &point) const;

        /// \param point_index Индекс узла сетки, для которой мы хотим узнать соответствующий материал.
        /// \return Номер материала, соответствующего узлу.
        /// \remarks Если точка лежит на границе между материалами, функция может вернуть индекс любого из этих материалов.
        int pointMaterial(int point_index) const {return m_PointMaterial[point_index].first();}

        /// \param point_index Индекс узла сетки, для которой мы хотим узнать соответствующие материалы.
        /// \return Список материалов, соответствующих узлу сетки.
        /// \remarks Если точка лежит на границе материалов, в списке будут индексы всех этих материалов. В противном случае
        /// в списке будет только один элемент.
        const QList<int>& pointMaterials(int point_index) const {return m_PointMaterial[point_index];}

        /// Проверка, находится ли точка на границе между какими-либо материалами.
        /// \return \b true, если точка лежит на границе между несколькими материалами и \b false в противном случае.
        bool pointBelongBoundary(int point_index) const {
            return m_PointMaterial[point_index].size() != 1? true : false;
        }

        /// Проверка, находится ли точка на границе между заданными материалами.
        /// \return \b true, если точка лежит на границе между \e material_1 и \e material_2 и \b false в противном случае.
        bool pointBelongBoundary(int point_index, int material_1, int material_2) const {
            return m_PointMaterial[point_index].contains(material_1) && m_PointMaterial[point_index].contains(material_2);
        }

    private:
        int m_RectPerRow;           ///< Число "зон поиска" по горизонтали.
        int m_RectPerColumn;        ///< Число "зон поиска" по вертикали.
        double m_RectangleWidth;    ///< Ширина "зоны поиска".
        double m_RectangleHeight;   ///< Высота "зоны поиска".
        QList<int> **m_GridContent; ///< [i,j] элемент массива содержит список треугольников, хотя бы частично лежащих в [i,j] "зоне поиска".

        /// Информация о том, какому материалу соответствует узел конечноэлементной сетки.
        //
        /// При использовании стандартных структур данных понятие "материал" привязывается к конечным элементам, а не к узлам
        /// сетки, и это логично. Но иногда возникает необходимость обработать только те узлы сетки, которые находятся в области,
        /// соответствующей конкретному материалу, или только те узлы, которые лежат на границе между двумя материалами.
        /// Данная структура данных хранит для каждого узла сетки номер материала, которому этот узел соответствует. Если узел
        /// лежит на границе между несколькими материалами, то считается, что он соответствует всем этим материалам.
        QVector< QList<int> > m_PointMaterial;
    };
}

#endif // _FEM_TRIANGLENET_SEARCH_
